package server.datamodel;

import java.util.HashSet;

public class Creep {

	private Cell cell;
	private int health = 1;
	private int healthForSimulation = 1;
	private boolean slowed;
	private boolean slowedForSimulation;
	private int slowTime;
	private int slowTimeForSimulation;
	private double speed;
	private double speedForSimulation;
	private float walkedDistance;
	private float walkedDistanceForSimulation;
	private Waypoint currentWaypoint;
	private Waypoint currentWaypointForSimulation;
	private UserAssets userAssets;
	private float worldX;
	private float posXForSimulation;
	private float worldZ;
	private float posZForSimulation;
	private float[] vector;
	private float[] vectorForSimulation;
	private float speedMult; //this is used to balance speed
	private float speedMultForSimulation;
	private CreepDescription creepDescription;
	private String ID;
	private String type;
	private String name;
	private boolean newInField;
	
	private HashSet<Tower> firedOn = new HashSet<Tower>();
	
	public Creep(String ID) {
		this.ID = ID;
		vector = new float[2];
		vectorForSimulation = new float[2];
	}
	
	@Override
	public String toString() {
		return ID;
	}
	
	public void setCell(Cell cell) {
		if(this.cell != cell) {
			if(getCell() != null) {
				getCell().removeCreep(this);
			}
			this.cell= cell;
			if(getCell() != null) {
				getCell().addCreep(this);
			}
		}
	}
	
	public Cell getCell() {
		return cell;
	}
	
	public void setUserAssets(UserAssets userAssets) {
		if(this.userAssets != userAssets) {
			if(getUserAssets() != null) {
				getUserAssets().removeCreep(this);
			}
			this.userAssets = userAssets;
			if(getUserAssets() != null) {
				getUserAssets().addCreep(this);
			}
		}
	}
	
	public UserAssets getUserAssets() {
		return userAssets;
	}

	public int getHealth() {
		return health;
	}

	public void setHealth(int health) {
		this.health = health;
	}

	public boolean isSlowed() {
		return slowed;
	}

	public void setSlowed(boolean slowed) {
		this.slowed = slowed;
	}

	public int getSlowTime() {
		return slowTime;
	}

	public void setSlowTime(int slowTime) {
		this.slowTime = slowTime;
	}

	public double getSpeed() {
		return speed;
	}

	public void setSpeed(double speed) {
		this.speed = speed;
	}

	public Waypoint getCurrentWaypoint() {
		return currentWaypoint;
	}

	public void setCurrentWaypoint(Waypoint currentWaypoint) {
		if(currentWaypoint.getMap().getEnterWaypoint() == currentWaypoint) {
			newInField = true;
		}
		
		worldX = currentWaypoint.getWorldX();
		worldZ = currentWaypoint.getWorldY();
		walkedDistance = 0;
		vector[0] = -(float)Math.cos(Math.toRadians(currentWaypoint.getRotateUnit() - 90));
		vector[1] = (float)Math.sin(Math.toRadians(currentWaypoint.getRotateUnit() - 90));
		
		if(currentWaypoint.getRotateUnit() % 90 == 0) {
			speedMult = 1;
		} else {
			speedMult = 1 / (float)Math.sqrt(2);
		}
		
		this.currentWaypoint = currentWaypoint;
	}

	public float getWorldX() {
		return worldX;
	}

	public void setWorldX(float worldX) {
		this.worldX = worldX;
	}

	public float getWorldZ() {
		return worldZ;
	}

	public void setWorldZ(float worldZ) {
		this.worldZ = worldZ;
	}

	public void setFiredOn(HashSet<Tower> firedOn) {
		this.firedOn = firedOn;
	}
	
	public HashSet<Tower> getFiredOn() {
		return firedOn;
	}
	
	public void addFiredOn(Tower tower) {
		if(firedOn.add(tower)) {
			tower.setFiresOn(this);
		}
	}
	
	public void removeFiredOn(Tower tower) {
		if(firedOn.remove(tower)) {
			tower.setFiresOn(null);
		}
	}
	
	public float getWalkedDistance() {
		return walkedDistance;
	}
	
	public void addToWalkedDistance(float addToWalkedDistance) {
		this.walkedDistance += addToWalkedDistance * speedMult;
	}
	
	public void setWalkedDistance(float walkedDistance) {
		this.walkedDistance = walkedDistance;
	}
	
	public float[] getVector() {
		return vector;
	}
	
	public void setCreepDescription(CreepDescription creepDescription) {
		this.creepDescription = creepDescription;
	}
	
	public CreepDescription getCreepDescription() {
		return creepDescription;
	}
	
	public String getID() {
		return ID;
	}
	
	public void setType(String type) {
		this.type = type;
	}
	
	public String getType() {
		return type;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public float getSpeedMult() {
		return speedMult;
	}
	
	public boolean isNewInField() {
		boolean f = newInField;
		newInField = false;
		return f;
	}

	/**************************************************************************
	 * getter and setter for simulation
	 **************************************************************************/
	public void setHealthForSimulation(int healthForSimulation) {
		this.healthForSimulation = healthForSimulation;
	}

	public int getHealthForSimulation() {
		return healthForSimulation;
	}

	public void setSlowedForSimulation(boolean slowedForSimulation) {
		this.slowedForSimulation = slowedForSimulation;
	}

	public boolean isSlowedForSimulation() {
		return slowedForSimulation;
	}

	public void setSlowTimeForSimulation(int slowTimeForSimulation) {
		this.slowTimeForSimulation = slowTimeForSimulation;
	}

	public int getSlowTimeForSimulation() {
		return slowTimeForSimulation;
	}

	public void setSpeedForSimulation(double speedForSimulation) {
		this.speedForSimulation = speedForSimulation;
	}

	public double getSpeedForSimulation() {
		return speedForSimulation;
	}

	public void setWalkedDistanceForSimulation(float walkedDistanceForSimulation) {
		this.walkedDistanceForSimulation = walkedDistanceForSimulation;
	}
	
	public void addToWalkedDistanceForSimulation(float addToWalkedDistance) {
		this.walkedDistanceForSimulation += addToWalkedDistance * speedMultForSimulation;
	}

	public float getWalkedDistanceForSimulation() {
		return walkedDistanceForSimulation;
	}

	public void setCurrentWaypointForSimulation(
			Waypoint currentWaypointForSimulation) {
		posXForSimulation = currentWaypointForSimulation.getCell().getX();
		posZForSimulation = currentWaypointForSimulation.getCell().getY();
		vectorForSimulation[0] = -(float)Math.cos(Math.toRadians(currentWaypointForSimulation.getRotateUnit() - 90));
		vectorForSimulation[1] = (float)Math.sin(Math.toRadians(currentWaypointForSimulation.getRotateUnit() - 90));
		walkedDistanceForSimulation = 0;
		
		if(currentWaypointForSimulation.getRotateUnit() % 90 == 0) {
			speedMultForSimulation = 1;
		} else {
			speedMultForSimulation = 1 / (float)Math.sqrt(2);
		}
		
		this.currentWaypointForSimulation = currentWaypointForSimulation;
	}

	public Waypoint getCurrentWaypointForSimulation() {
		return currentWaypointForSimulation;
	}

	public void setPosXForSimulation(float posXForSimulation) {
		this.posXForSimulation = posXForSimulation;
	}

	public float getPosXForSimulation() {
		return posXForSimulation;
	}

	public void setPosZForSimulation(float posZForSimulation) {
		this.posZForSimulation = posZForSimulation;
	}

	public float getPosZForSimulation() {
		return posZForSimulation;
	}
	
	public float[] getVectorForSimulation() {
		return vectorForSimulation;
	}
	
	public float getSpeedMultForSimulation() {
		return speedMultForSimulation;
	}
	
	public void setSpeedMult(float speedMult) {
		this.speedMult = speedMult;
	}
}
